﻿using System;
using System.Collections.ObjectModel;
using System.Windows.Input;
using Peter.Common;
using Peter.Common.MainMenu;
using Peter.Sdw.Data;
using Peter.Sdw.Logic.Dialogs;

namespace Peter.Sdw.Logic
{
   /// <summary>
   /// The main view model for SDW.
   /// </summary>
   public sealed class SdwMainModel : PeterToolWindow
   {
      /// <summary>
      /// Gets the guid for this dock item.
      /// </summary>
      public const string GUID = "07AD15C4-1988-4592-AD80-F2F12421A3EE";

      private int m_Start;
      private bool m_IsLoading;
      private bool m_IsLoginVisible;
      private LightModel m_SelectedLight;
      private LoginModel m_LoginDialog;
      private RelayCommand m_CmdLogin;
      private RelayCommand m_CmdRefresh;
      private RelayCommand m_CmdAddLight;
      private RelayCommand m_CmdEditLight;
      private RelayCommand m_CmdNavResults;
      private static SelectTermModel s_SelectTermDialog;
      private readonly ObservableCollection<LightModel> m_Lights;

      /// <summary>
      /// Initializes a new main view model.
      /// </summary>
      public SdwMainModel ()
      {
         this.ContentId = GUID;
         this.Icon = MainMenuIcon.LightbulbIdea;
         this.Title = "Seek Deep Within";
         this.m_IsLoginVisible = true;
         this.m_Lights = new ObservableCollection<LightModel> ();
         WebQueue.Instance.WebGetComplete += this.OnGetCompleted;
         WebQueue.Instance.WebPostComplete += this.OnPostCompleted;
      }

      /// <summary>
      /// Gets the term selector.
      /// </summary>
      public static SelectTermModel TermSelector
      {
         get { return s_SelectTermDialog ?? (s_SelectTermDialog = new SelectTermModel ()); }
      }

      /// <summary>
      /// Gets the list of available lights.
      /// </summary>
      public ObservableCollection<LightModel> Lights { get { return m_Lights; } }

      /// <summary>
      /// Gets the command used to refresh the list.
      /// </summary>
      public ICommand RefreshCommand
      {
         get { return this.m_CmdRefresh ?? (this.m_CmdRefresh = new RelayCommand (this.OnRefresh, this.CanRefresh)); }
      }

      /// <summary>
      /// Gets the command to edit a light.
      /// </summary>
      public ICommand EditLightCommand
      {
         get { return this.m_CmdEditLight ?? (this.m_CmdEditLight = new RelayCommand (this.OnEditLight)); }
      }

      /// <summary>
      /// Gets the command to add a new light.
      /// </summary>
      public ICommand AddLightCommand
      {
         get { return this.m_CmdAddLight ?? (this.m_CmdAddLight = new RelayCommand (this.OnAddLight, this.CanRefresh)); }
      }

      /// <summary>
      /// Gets the command to login.
      /// </summary>
      public ICommand LoginCommand
      {
         get { return m_CmdLogin ?? (this.m_CmdLogin = new RelayCommand (this.OnLogin)); }
      }

      /// <summary>
      /// Gets the command to navigate the results.
      /// </summary>
      public ICommand NavigateListCommand
      {
         get { return this.m_CmdNavResults ?? (this.m_CmdNavResults = new RelayCommand (this.OnNavigateResults, this.CanNavigateResults)); }
      }

      /// <summary>
      /// Gets or Sets if we are loading data.
      /// </summary>
      public bool IsLoading
      {
         get { return this.m_IsLoading; }
         set
         {
            this.m_IsLoading = value;
            this.RaisePropertyChanged ("IsLoading");
         }
      }

      /// <summary>
      /// Gets or Sets the selected light.
      /// </summary>
      public LightModel SelectedLight
      {
         get { return this.m_SelectedLight; }
         set
         {
            this.m_SelectedLight = value;
            this.RaisePropertyChanged ("SelectedLight");
         }
      }

      /// <summary>
      /// Gets or Sets if the login button is visible or not.
      /// </summary>
      public bool IsLoginVisible
      {
         get { return this.m_IsLoginVisible; }
         set
         {
            this.m_IsLoginVisible = value;
            this.RaisePropertyChanged ("IsLoginVisible");
         }
      }

      private bool CanRefresh (object obj)
      {
         return !this.IsLoginVisible;
      }

      /// <summary>
      /// Edits the selected light.
      /// </summary>
      /// <param name="obj">Command parameter</param>
      private void OnEditLight (object obj)
      {
         if (this.SelectedLight == null) return;
         this.SelectedLight.IsActive = true;
         this.SelectedLight.IsSelected = true;
         this.Peter.AddDocument (this.SelectedLight);
         this.SelectedLight.GetLove ();
      }

      /// <summary>
      /// Adds a new light.
      /// </summary>
      /// <param name="obj">Command parameter</param>
      private void OnAddLight (object obj)
      {
         var model = new LightModel ();
         this.Lights.Add (model);
         model.IsActive = true;
         model.IsSelected = true;
         this.Peter.AddDocument (model);
      }

      /// <summary>
      /// Refreshes the list of light.
      /// </summary>
      /// <param name="obj">Command parameter</param>
      private void OnRefresh (object obj)
      {
         this.GetLights ();
      }

      /// <summary>
      /// Shows the user login window.
      /// </summary>
      /// <param name="obj">Command parameter.</param>
      private void OnLogin (object obj)
      {
         if (this.m_LoginDialog == null)
            this.m_LoginDialog = new LoginModel ();
         this.m_LoginDialog.GetToken ();
         this.Peter.ShowDialog (this.m_LoginDialog);
      }

      /// <summary>
      /// Checks to see if the list can be navigated
      /// </summary>
      /// <param name="obj">Command parameter</param>
      /// <returns>True if the command can execute, otherwise false.</returns>
      private bool CanNavigateResults (object obj)
      {
         var dir = obj.ToString ();
         if (dir == "prev")
            return this.m_Start > 0;
         return this.Lights.Count >= 25;
      }

      /// <summary>
      /// Navigates the list of results.
      /// </summary>
      /// <param name="obj">Command parameter</param>
      private void OnNavigateResults (object obj)
      {
         var dir = obj.ToString ();
         if (dir == "prev")
            this.m_Start -= 25;
         else
            this.m_Start += 25;
         this.GetLights ();
      }

      /// <summary>
      /// Gets the list of lights from the server.
      /// </summary>
      private void GetLights ()
      {
         this.Lights.Clear ();
         this.IsLoading = true;
         WebQueue.Instance.WebGetComplete += this.OnGetCompleted;
         WebQueue.Instance.Get (string.Format (Constants.URL_GET_LIGHT, this.m_Start, string.Empty));
      }

      /// <summary>
      /// Occurs when a web get request is completed.
      /// </summary>
      /// <param name="sender">WebQueue.</param>
      /// <param name="e">WebRequestEventArgs</param>
      private void OnGetCompleted (object sender, WebRequestEventArgs e)
      {
         try {
            if (e.Url == string.Format (Constants.URL_GET_LIGHT, this.m_Start, string.Empty)) {
               if (e.Response.status == Constants.SUCCESS) {
                  foreach (var light in e.Response.lights) {
                     this.Lights.Add (new LightModel {
                        Id = light.id,
                        Name = light.name,
                        ShowInLibrary = light.ShowInLibrary,
                        ShowInGlossary = light.ShowInGlossary
                     });
                  }
               }
               foreach (var model in this.Lights) {
                  model.OkToUpdate = true;
               }
               this.IsLoading = false;
            }
         } catch (Exception ex) {
            Console.Error.WriteLine (ex.Message);
         }
      }

      /// <summary>
      /// Occurs when a web post request is completed.
      /// </summary>
      /// <param name="sender">WebQueue.</param>
      /// <param name="e">WebRequestEventArgs</param>
      private void OnPostCompleted (object sender, WebRequestEventArgs e)
      {
         if (e.Url == Constants.URL_LOGIN_REQUEST) {
            if (e.Response.status == Constants.SUCCESS) {
               WebQueue.Instance.Get (Constants.URL_GET_TOKEN);
               this.GetLights ();
               this.IsLoginVisible = false;
               CommandManager.InvalidateRequerySuggested ();
            }
         }
      }
   }
}
